'''
Created on Apr 11, 2012

@author: ke
'''

from google.appengine.ext import webapp
#from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
#from google.appengine.ext.db import djangoforms
from google.appengine.api import users
import urllib2
import numpy as np
import csv
from history import QueryHistory
import datetime


class Markowitz(webapp.RequestHandler):
    
    def get_historical_data(self, ticker='YHOO'):
        #get historical data for the specified stock from Yahoo Finance
        
        url = 'http://ichart.yahoo.com/table.csv?s='+ticker
        page = urllib2.urlopen(url)
        csv_reader = csv.reader(page)
        
        header = csv_reader.next()
        
        dt=[(header[0], np.datetime_),
                   (header[1], np.float16),
                   (header[2], np.float16),
                   (header[3], np.float16),
                   (header[4], np.float16),
                   (header[5], np.int32),
                   (header[6], np.float16),
                   ]
        
        historical_price = np.array([tuple(row) for row in csv_reader], dtype=dt)
        return historical_price
    
    def get_daily_returns(self, historical_data):
        #Convert historical data into daily price change
        
        daily_close = historical_data['Close'][::-1]
        today_price = daily_close[1:]
        yesterday_price = daily_close[0:-1]
        yesterday_price = yesterday_price + np.ones(yesterday_price.shape)*0.000000000000000000000000000001
        daily_return = (today_price - yesterday_price)/yesterday_price
        return daily_return
    
    def get_covariance_matrix(self, daily_return_dict):
        daily_return_list=[]
        ticker_list= daily_return_dict.keys()
        mean_return_list=[]
        for t in ticker_list:
            daily_return_list.append(daily_return_dict[t])
            mean_return_list.append(np.mean(daily_return_dict[t]))
        covariance_matrix = np.cov(daily_return_list)
        mean_return_list=np.array(mean_return_list).T
        return (ticker_list, covariance_matrix, mean_return_list)
    
    def get_daily_return_dict(self, stock_ticker_list=['YHOO','GOOG','AAPL'], length=100):
        #get all historical daily return data into a dictionary format
        daily_return_dict = {}
        max_length=length
        for t in stock_ticker_list:
            hd=self.get_historical_data(ticker=t)
            dr=list(self.get_daily_returns(historical_data=hd))
            max_length=min(len(dr), max_length)
            daily_return_dict.setdefault(t,[])
            daily_return_dict[t]=dr
        for key in daily_return_dict:
            daily_return_dict[key]=daily_return_dict[key][0:max_length]
        return daily_return_dict
            
    
    def get_optimal_weight_with_short(self, cov, mean, expected_r, header):
        #return the optimal weight when short sale is allowed (negative weight)
        result = {}
        
        A = np.dot(np.dot(np.ones(cov.shape[1]).T, np.linalg.pinv(cov)),mean)
        B = np.dot(np.dot(mean.T, np.linalg.pinv(cov)),mean)
        C = np.dot(np.dot(np.ones(cov.shape[1]).T, np.linalg.pinv(cov)), np.ones(cov.shape[1]))
        D = B*C-A*A
        cov1 = np.dot(np.linalg.pinv(cov), np.ones(cov.shape[1]))
        cov_mu = np.dot(np.linalg.pinv(cov), mean)
        wt = list((1/D)*(B*(cov1) - A*(cov_mu)) + (1/D)*(C*(cov_mu) - A*(cov1))*expected_r)
        
        i=0
        for t in list(header):
            result.setdefault(t)
            result[t] = wt[i]
            i=i+1
        
        return result
    
    def get(self):
        #current: getting the covariance matrix and average daily return calculated
        #html = template.render('templates/form_start.html', {})
        #html = html + str(InputForm())
        #html = html + template.render('templates/form_end.html', {'sub_title':'submit'})
        html =template.render('templates/markowitz_form.html', {})
        self.response.out.write(html)
        
    
    
    def post(self):       
        
        tickers = self.request.get('stock_tickers').replace(' ','').upper().encode('ascii', 'ignore').split(';')
        if len(tickers) < 2:
            self.response.out.write('invalid ticker; use YHOO, GOOG, AAPL instead')
            tickers=['YHOO','GOOG','AAPL']
        
        try:
            flight = max(100, int(self.request.get('length')))
        except:
            self.response.out.write('invalid length; use 100 instead')
            flight = 100
        
        try:
            rate = max(0.0001,float(self.request.get('expected_return')))
        except:
            self.response.out.write('invalid expected return; use 0.01 instead')
            rate = 0.01
        
        stock_data=self.get_daily_return_dict(stock_ticker_list=tickers, length=flight)
        (tl, cm, mr) = self.get_covariance_matrix(daily_return_dict=stock_data)
        
        wt = self.get_optimal_weight_with_short(cov=cm, mean=mr, expected_r=rate, header=tl)
        
        self.response.headers['Content-Type'] = 'text/plain'
        for key, value in wt.items():
            self.response.out.write([key, value])
        
        new_queryHistory = QueryHistory()
        new_queryHistory.stock_tickers = ";".join(tickers)
        new_queryHistory.length = flight
        new_queryHistory.expected_return = rate
        new_queryHistory.user = users.get_current_user()
        new_queryHistory.query_date = datetime.date.today()
        
        new_queryHistory.put()